
namespace Patterns4Net.Tests.Core.CecilExtensions
{
    using System;
    using System.Linq;
    using Mono.Cecil;
    using NUnit.Framework;
    using Patterns4Net.Core.CecilExtensions;
    using Patterns4Net.Attributes.Relations;

    [TestFixture]
    public class PropertyExtensionsTests
    {
        [Test]
        public void GetAutoImplementedBackingField_Returns_Null_For_PropertyWithBackingField()
        {
            var property = GetProperty("PropertyWithBackingField");
            var field = property.GetAutoImplementedBackingField();
            Assert.IsNull(field);
        }

        [Test]
        public void GetAutoImplementedBackingField_Returns_Null_For_Calculated()
        {
            var property = GetProperty("Calculated");
            var field = property.GetAutoImplementedBackingField();
            Assert.IsNull(field);
        }

        [Test]
        public void GetAutoImplementedBackingField_Returns_BackingField_For_AutoProperty()
        {
            var property = GetProperty("AutoProperty");
            var field = property.GetAutoImplementedBackingField();
            Assert.IsNotNull(field);
        }

        [Test]
        public void HasAttribute_With_Uses_Returns_True_For_AutoPropertys_Backing_Field()
        {
            var backingField = typeof(Spike).GetTypeDefinition().Fields.FirstOrDefault(f => f.FieldType.Name == "Int32");
            Assert.IsTrue(backingField.HasAttribute<UsesAttribute>());
        }

        [Test]
        public void HasAttribute_With_Uses_Returns_True_For_Regular_BackingField()
        {
            var backingField = typeof(Spike).GetTypeDefinition().Fields.FirstOrDefault(f => f.Name == "backingField");
            Assert.IsFalse(backingField.HasAttribute<UsesAttribute>());
        }

        private static PropertyDefinition GetProperty(string name)
        {
            return typeof(Spike).GetTypeDefinition().Properties.FirstOrDefault(x => x.Name == name);            
        }

        public class Spike
        {
            [Uses]
            public int AutoProperty { get; private set; }

            private double backingField;

            public double PropertyWithBackingField
            {
                get { return this.backingField; }
                set { this.backingField = value + 1; }
            }

            public double Calculated
            {
                get
                {
                    return Math.PI * Math.E / this.backingField;
                }
            }
        }
    }
}
